home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 May / EnigmA AMIGA RUN 27 (1998)(G.R. Edizioni)(IT)[!][issue 1998-05].iso / recent1 / gifani.lha / gifanim_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  1998-04-13  |  93KB  |  2,502 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 2.2 (13.4.98)
  5. **  gifanim.datatype 2.2
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1997/1998 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /* ansi includes */
  19. #include <limits.h>
  20.  
  21. /*****************************************************************************/
  22. /* debugging */
  23.  
  24. #if 0
  25. void kprintf( STRPTR, ... );
  26. #define D( x ) x
  27. #else
  28. #define D( x )
  29. #endif
  30.  
  31. /*****************************************************************************/
  32.  
  33. /* decoder related local prototypes */
  34. static BOOL             ReadColorMap( struct ClassBase *, struct GIFAnimInstData *, UWORD, struct ColorRegister * );
  35. static void             DoExtension( struct ClassBase *, Object *, struct GIFAnimInstData *, TEXT );
  36. static int              GetDataBlock( struct ClassBase *, struct GIFAnimInstData *, UBYTE * );
  37. static int              GetCode( struct ClassBase *, struct GIFAnimInstData *, int, BOOL );
  38. static int              LWZReadByte( struct ClassBase *, struct GIFAnimInstData *, BOOL, int );
  39. static void             ReadImage( struct ClassBase *, struct GIFAnimInstData *, UBYTE *, UWORD, UWORD, UWORD, UWORD, UWORD, BOOL, BOOL, UWORD );
  40. static void             WriteDeltaPixelArray8Fast( struct BitMap *, UBYTE *, UBYTE * );
  41. static int              getbase2( int );
  42. static BOOL             ReadOK( struct ClassBase *, struct GIFDecoder *, void *, ULONG );
  43.  
  44. /*****************************************************************************/
  45.  
  46. /* local prototypes */
  47. static                 BOOL                 ScanFrames( struct ClassBase *, Object * );
  48. static                 struct FrameNode    *AllocFrameNode( struct ClassBase *, APTR );
  49. static                 struct FrameNode    *FindFrameNode( struct MinList *, ULONG );
  50. static                 void                 FreeFrameNodeResources( struct ClassBase *, struct GIFAnimInstData * );
  51. static                 struct BitMap       *AllocFrameBitMap( struct ClassBase *, struct GIFAnimInstData * );
  52. static                 void                 FreeFrameBitMap( struct ClassBase *, struct GIFAnimInstData *, struct BitMap * );
  53. static                 struct BitMap       *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
  54. static                 struct FrameNode    *GetPrevFrameNode( struct FrameNode *, ULONG );
  55. static                 void                 AttachSample( struct ClassBase *, struct GIFAnimInstData * );
  56.  
  57. /*****************************************************************************/
  58.  
  59. /* Create "gifanim.datatype" BOOPSI class */
  60. struct IClass *initClass( struct ClassBase *cb )
  61. {
  62.     struct IClass *cl;
  63.  
  64.     /* Create our class... */
  65.     if( cl = MakeClass( GIFANIMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct GIFAnimInstData ), 0UL ) )
  66.     {
  67. #define DTSTACKSIZE (16384UL)
  68.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  69.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  70.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  71.       cl -> cl_UserData                = (ULONG)cb;
  72.  
  73.       AddClass( cl );
  74.     }
  75.  
  76.     return( cl );
  77. }
  78.  
  79.  
  80. /* class dispatcher */
  81. DISPATCHERFLAGS
  82. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  83. {
  84.     struct ClassBase        *cb = (struct ClassBase *)(cl -> cl_UserData);
  85.     struct GIFAnimInstData  *gaid;
  86.     ULONG                    retval = 0UL;
  87.  
  88.     switch( msg -> MethodID )
  89.     {
  90. /****** gifanim.datatype/OM_NEW **********************************************
  91. *
  92. *    NAME
  93. *        OM_NEW -- Create a gifanim.datatype object.
  94. *
  95. *    FUNCTION
  96. *        The OM_NEW method is used to create an instance of the
  97. *        gifanim.datatype class.  This method is passed to the superclass
  98. *        first. After this, gifanim.datatype parses the prefs file and makes
  99. *        a scan through the data to get index information. Frame bitmaps are
  100. *        loaded if the input stream isn't seekable, colormaps and the first
  101. *        frame are loaded immediately.
  102. *        If a sample was set in the prefs, it will be loaded and attached
  103. *        to the animation.
  104. *
  105. *    ATTRIBUTES
  106. *        The following attributes can be specified at creation time.
  107. *
  108. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  109. *            attribute. Only DTST_FILE and DTST_RAM are supported.
  110. *            If any other type was set in a given DTA_SourceType,
  111. *            OM_NEW will be rejected.
  112. *            Defaults to DTST_FILE.
  113. *
  114. *        DTA_Handle -- For DTST_FILE, a BPTR filehandle is expected. This
  115. *            handle will be created by datatypesclass depeding on the DTF_#?
  116. *            flag, which is DTF_BINARY here.  DTST_FILE, datatypesclass
  117. *            creates a file handle from the given DTA_Name and DTA_Handle
  118. *            (a BPTR returned by Lock).
  119. *            A DTST_RAM (create empty object) source type requires a NULL
  120. *            handle.
  121. *
  122. *    RESULT
  123. *        If the object was created a pointer to the object is returned,
  124. *        otherwise NULL is returned.
  125. *
  126. ******************************************************************************
  127. *
  128. */
  129.       case OM_NEW:
  130.       {
  131.           struct TagItem *ti;
  132.  
  133.           /* We only support DTST_FILE or DTST_RAM as source type */
  134.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  135.           {
  136.             if( ((ti -> ti_Data) != DTST_FILE) && ((ti -> ti_Data) != DTST_RAM) )
  137.             {
  138.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  139.  
  140.               break;
  141.             }
  142.           }
  143.  
  144.           if( retval = DoSuperMethodA( cl, o, msg ) )
  145.           {
  146.             /* Load frames... */
  147.             if( !ScanFrames( cb, (Object *)retval ) )
  148.             {
  149.               /* Something went fatally wrong, dispose object */
  150.               CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  151.               retval = 0UL;
  152.             }
  153.           }
  154.       }
  155.           break;
  156.  
  157. /****** gifanim.datatype/OM_DISPOSE ******************************************
  158. *
  159. *    NAME
  160. *        OM_DISPOSE -- Delete a gifanim.datatype object.
  161. *
  162. *    FUNCTION
  163. *        The OM_DISPOSE method is used to delete an instance of the
  164. *        gifanim.datatype class. This method is passed to the superclass when
  165. *        it has completed.
  166. *        This method frees all frame nodes and their contents (bitmaps,
  167. *        colormaps, samples etc.)
  168. *
  169. *    RESULT
  170. *        The object is deleted. 0UL is returned.
  171. *
  172. ******************************************************************************
  173. *
  174. */
  175.       case OM_DISPOSE:
  176.       {
  177.           LONG saved_ioerr = IoErr();
  178.  
  179.           /* Get a pointer to our object data */
  180.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  181.  
  182.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  183.           WaitBlit();
  184.  
  185.           /* Free colormaps etc. (e.g. all resources which are NOT free'ed on DeletePool below) */
  186.           FreeFrameNodeResources( cb, gaid );
  187.  
  188.           /* Free our key bitmap */
  189.           FreeBitMap( (gaid -> gaid_KeyBitMap) );
  190.  
  191.           /* Delete the frame pool */
  192.           DeletePool( (gaid -> gaid_Pool) );
  193.  
  194.           /* Close input file */
  195.           if( gaid -> gaid_FH )
  196.           {
  197.             Close( (gaid -> gaid_FH) );
  198.           }
  199.  
  200.           /* Close verbose output file */
  201.           if( gaid -> gaid_VerboseOutput )
  202.           {
  203.             Close( (gaid -> gaid_VerboseOutput) );
  204.           }
  205.  
  206.           /* Dispose object */
  207.           DoSuperMethodA( cl, o, msg );
  208.  
  209.           /* Restore Result2 */
  210.           SetIoErr( saved_ioerr );
  211.       }
  212.           break;
  213.  
  214. /* TEST TEST / Support for format change "on-the-fly" disabled here / TEST TEST  */
  215. #ifdef COMMENTED_OUT
  216.       case DTM_FRAMEBOX:
  217.       {
  218.           struct dtFrameBox *dtf = (struct dtFrameBox *)msg;
  219.  
  220.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  221.  
  222.           /* pass to superclas first */
  223.           retval = DoSuperMethodA( cl, o, msg );
  224.  
  225.           /* Does someone tell me in what for an environment (screen) I'll be attached to ? */
  226.           if( (dtf -> dtf_FrameFlags) & FRAMEF_SPECIFY )
  227.           {
  228.             if( dtf -> dtf_ContentsInfo )
  229.             {
  230.               if( dtf -> dtf_ContentsInfo -> fri_Screen )
  231.               {
  232.                 struct BitMap *bm = dtf -> dtf_ContentsInfo -> fri_Screen -> RastPort . BitMap;
  233.  
  234.                 /* Does we have a non-planar bitmap ? */
  235.                 if( !(GetBitMapAttr( bm, BMA_FLAGS ) & BMF_STANDARD) )
  236.                 {
  237.                   /* I assume here that the system is able to map a 24 bit bitmap into the screen
  238.                    * if it is deeper than 8 bit.
  239.                    */
  240.                   if( ((bm -> Depth) > 8UL) && ((dtf -> dtf_ContentsInfo -> fri_Dimensions . Depth) > 8UL) )
  241.                   {
  242.                     verbose_printf( cb, gaid, "using chunky bitmap\n" );
  243.                   }
  244.                 }
  245.               }
  246.             }
  247.           }
  248.       }
  249.           break;
  250. #endif /* COMMENTED_OUT */
  251.  
  252.       case OM_UPDATE:
  253.       {
  254.           if( DoMethod( o, ICM_CHECKLOOP ) )
  255.           {
  256.             break;
  257.           }
  258.       }
  259.       case OM_SET:
  260.       {
  261.           /* Pass the attributes to the animation class and force a refresh if we need it */
  262.           if( retval = DoSuperMethodA( cl, o, msg ) )
  263.           {
  264.             /* Top instance ? */
  265.             if( OCLASS( o ) == cl )
  266.             {
  267.               struct RastPort *rp;
  268.  
  269.               /* Get a pointer to the rastport */
  270.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  271.               {
  272.                 struct gpRender gpr;
  273.  
  274.                 /* Force a redraw */
  275.                 gpr . MethodID   = GM_RENDER;
  276.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  277.                 gpr . gpr_RPort  = rp;
  278.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  279.  
  280.                 DoMethodA( o, (Msg)(&gpr) );
  281.  
  282.                 /* Release the temporary rastport */
  283.                 ReleaseGIRPort( rp );
  284.  
  285.                 /* We did a refresh... */
  286.                 retval = 0UL;
  287.               }
  288.             }
  289.           }
  290.       }
  291.           break;
  292.  
  293. /****** gifanim.datatype/DTM_WRITE *******************************************
  294. *
  295. *    NAME
  296. *        DTM_WRITE -- Save data
  297. *
  298. *    FUNCTION
  299. *        This method saves the object's contents to disk.
  300. *
  301. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  302. *        superclass, animation.datatype, which writes a single IFF ILBM
  303. *        picture.
  304. *
  305. *        If dtw_mode is DTWM_RAW, the object saved an GIF Animation stream 
  306. *        to the filehandle given, starting with the current frame until
  307. *        the end is reached.
  308. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  309. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  310. *
  311. *    TAGS
  312. *        When writing the local ("raw") format, GIF Animation, the following
  313. *        attributes are recognized:
  314. *
  315. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  316. *            Defaults to the current frame displayed.
  317. *
  318. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  319. *            Defaults to (max_num_of_frames - curr_frame).
  320. *
  321. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  322. *            Defaults to 1, which means: "jump to next frame".
  323. *
  324. *    NOTE
  325. *        - Any sound attached to the animation will NOT be saved.
  326. *
  327. *        - A CTRL-D signal to the writing process aborts the save.
  328. *
  329. *    RESULT
  330. *        Returns 0 for failure (IoErr() returns result2), non-zero
  331. *        for success.
  332. *
  333. ******************************************************************************
  334. *
  335. */
  336.       case DTM_WRITE:
  337.       {
  338.           struct dtWrite *dtw;
  339.  
  340.           dtw = (struct dtWrite *)msg;
  341.  
  342.           /* Local data format requested ?... */
  343.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  344.           {
  345.             retval = SaveGIFAnim( cb, cl, o, dtw );
  346.           }
  347.           else
  348.           {
  349.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  350.             retval = DoSuperMethodA( cl, o, msg );
  351.           }
  352.       }
  353.           break;
  354.  
  355.  
  356. /****** gifanim.datatype/ADTM_LOADFRAME *****************************************
  357. *
  358. *    NAME
  359. *        ADTM_LOADFRAME -- Load frame
  360. *
  361. *    FUNCTION
  362. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  363. *        data of the animation.
  364. *        The given timestamp will be used to find a matching timestamp
  365. *        in the internal FrameNode list. If it was found, the corresponding
  366. *        timing, bitmap and colormap data are stored into the struct
  367. *        adtFrame. If the bitmap wasn't loaded, this method attempts to
  368. *        load it from disk.
  369. *
  370. *    RESULT
  371. *        the bitmap ptr if a bitmap was found,
  372. *        0 (and result2 with the reason).
  373. *
  374. ******************************************************************************
  375. *
  376. */
  377.       case ADTM_LOADFRAME:
  378.       {
  379.           struct adtFrame  *alf         = (struct adtFrame *)msg;
  380.           struct adtFrame   freeframe;
  381.           struct FrameNode *fn;
  382.           LONG              error       = 0L;
  383.  
  384.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  385.  
  386.           ObtainSemaphore( (&(gaid -> gaid_SigSem)) );
  387.  
  388.           /* Like "realloc": Free any given frame (the free is done AFTER the load to
  389.            * avoid that a frame which is loaded will be freed and then loaded again...
  390.            */
  391.           if( alf -> alf_UserData )
  392.           {
  393.             /* Copy message contents that we can call ADTM_UNLOADFRAME below */
  394.             freeframe = *alf;
  395.             alf -> alf_UserData = NULL; /* "freeframe" now owns the frame data to free ! */
  396.           }
  397.           else
  398.           {
  399.             /* No data to free... */
  400.             freeframe . alf_UserData = NULL;
  401.           }
  402.  
  403.           /* Find frame by timestamp */
  404.           if( fn = FindFrameNode( (&(gaid -> gaid_FrameList)), (alf -> alf_TimeStamp) ) )
  405.           {
  406.             /* Load bitmaps only if we don't cache the whole anim and
  407.              * if we have a filehandle to load from (an empty object created using DTST_RAM won't have this)...
  408.              */
  409.             if( (!(gaid -> gaid_LoadAll)) && (gaid -> gaid_FH) )
  410.             {
  411.               /* If no bitmap is loaded, load it... */
  412.               if( !(fn -> fn_BitMap) )
  413.               {
  414.                 ULONG animwidth  = (ULONG)(gaid -> gaid_PaddedWidth),
  415.                       animheight = (ULONG)(gaid -> gaid_Height);
  416.  
  417.                 /* Allocate array for chunkypixel data */
  418.                 if( fn -> fn_ChunkyMap = (UBYTE *)AllocVecPooled( cb, (gaid -> gaid_Pool), ((animwidth * animheight) + 256) ) )
  419.                 {
  420.                   /* Get a clean background to avoid that rubbish shows througth transparent parts */
  421.                   memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  422.  
  423.                   if( fn -> fn_BitMap = AllocFrameBitMap( cb, gaid ) )
  424.                   {
  425.                     struct FrameNode *worknode = fn;
  426.                     struct FrameNode *prevnode = NULL;
  427.                     ULONG             rollback = 0UL;
  428.                     UBYTE            *deltamap = NULL;
  429.  
  430.                     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  431.  
  432.                     /* See if we need a rollback (if TRUE, we copy (below) the previous chunkymap into our
  433.                      * current chunkymap as background. If Left/Top != 0 or transparent colors are present,
  434.                      * parts of this previous image will occur).
  435.                      */
  436.                     switch( fn -> fn_GIF89aDisposal )
  437.                     {
  438.                       case GIF89A_DISPOSE_NODISPOSE:
  439.                       case GIF89A_DISPOSE_RESTOREPREVIOUS:
  440.                       {
  441.                           do
  442.                           {
  443.                             worknode = GetPrevFrameNode( worknode, 1UL );
  444.  
  445.                             rollback++;
  446.                           } while( ((worknode -> fn_ChunkyMap) == NULL) && ((worknode -> fn_TimeStamp) != 0UL) );
  447.                       }
  448.                           break;
  449.                     }
  450.  
  451.                     if( ((worknode -> fn_ChunkyMap) == NULL) && ((worknode -> fn_TimeStamp) == 0UL) )
  452.                     {
  453.                       error_printf( cb, gaid, "first frame without bitmap ... !\n" );
  454.                     }
  455.  
  456.                     do
  457.                     {
  458.                       ULONG current = rollback;
  459.  
  460.                       worknode = fn;
  461.  
  462.                       while( current-- )
  463.                       {
  464.                         worknode = GetPrevFrameNode( worknode, 1UL );
  465.                       }
  466.  
  467.                       if( (worknode -> fn_ChunkyMap) && (worknode != fn) )
  468.                       {
  469.                         prevnode = worknode;
  470.                       }
  471.                       else
  472.                       {
  473.                         if( Seek( (gaid -> gaid_FH), ((worknode -> fn_BMOffset) - (gaid -> gaid_CurrFilePos)), OFFSET_CURRENT ) != (-1L) )
  474.                         {
  475.                           if( gifdec -> file_buffer = AllocVec( ((worknode -> fn_BMSize) + 16UL), MEMF_PUBLIC ) )
  476.                           {
  477.                             BOOL   useGlobalColormap;
  478.                             UWORD  bitPixel;
  479.                             UBYTE  buf[ 16 ];
  480.  
  481.                             /* Init buffer */
  482.                             gifdec -> buffer     = gifdec -> file_buffer;
  483.                             gifdec -> buffersize = worknode -> fn_BMSize;
  484.                             gifdec -> which_fh   = WHICHFH_BUFFER;
  485.  
  486.                             /* Fill buffer */
  487.                             if( Read( (gifdec -> file), (gifdec -> buffer), (gifdec -> buffersize) ) == (gifdec -> buffersize) )
  488.                             {
  489.                               if( !ReadOK( cb, gifdec, buf, 9 ) )
  490.                               {
  491.                                 error = IoErr();
  492.                                 D( kprintf( "couldn't read left/top/width/height\n" ) );
  493.                               }
  494.  
  495.                               useGlobalColormap = !BitSet( buf[ 8 ], LOCALCOLORMAP );
  496.  
  497.                               bitPixel = 1 << ((buf[ 8 ] & 0x07) + 1);
  498.  
  499.                               /* disposal method */
  500.                               switch( worknode -> fn_GIF89aDisposal )
  501.                               {
  502.                                 case GIF89A_DISPOSE_NOP:
  503.                                 {
  504.                                   /* Background not transparent ? */
  505.                                   if( ((worknode -> fn_GIF89aTransparent) == ~0U) ||
  506.                                       ((worknode -> fn_GIF89aTransparent) != 0U) )
  507.                                   {
  508.                                     /* Restore to color 0 */
  509.                                     memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  510.                                   }
  511.                                 }
  512.                                     break;
  513.  
  514.                                 case GIF89A_DISPOSE_NODISPOSE:
  515.                                 {
  516.                                     /* do not dispose prev image */
  517.  
  518.                                     /* Check if we have a prevnode link to the previous image.
  519.                                      * If this is NULL, we assume that our chunkymap already contain
  520.                                      * the previous image
  521.                                      */
  522.                                     if( prevnode )
  523.                                     {
  524.                                       CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  525. #ifdef DELTAWPA8
  526.                                       CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  527.                                       deltamap = prevnode -> fn_ChunkyMap;
  528. #endif /* DELTAWPA8 */
  529.                                     }
  530.                                     else
  531.                                     {
  532. #ifdef DELTAWPA8
  533.                                       deltamap = NULL;
  534. #endif /* DELTAWPA8 */
  535.                                     }
  536.                                 }
  537.                                     break;
  538.  
  539.                                 case GIF89A_DISPOSE_RESTOREBACKGROUND:
  540.                                 {
  541.                                     /* Background not transparent ? */
  542.                                     if( ((worknode -> fn_GIF89aTransparent) == ~0U) ||
  543.                                         ((worknode -> fn_GIF89aTransparent) != (gaid -> gaid_GIFDec . GifScreen . Background)) )
  544.                                     {
  545.                                       /* Restore to background color */
  546.                                       memset( (fn -> fn_ChunkyMap), (gaid -> gaid_GIFDec . GifScreen . Background), (size_t)(animwidth * animheight) );
  547.                                     }
  548.                                 }
  549.                                     break;
  550.  
  551.                                 case GIF89A_DISPOSE_RESTOREPREVIOUS:
  552.                                 {
  553.                                     /* restore image of previous frame */
  554.  
  555.                                     /* Check if we have a prevnode link to the previous image.
  556.                                      * If this is NULL, we assume that our chunkymap already contain
  557.                                      * the previous image
  558.                                      */
  559.                                     if( prevnode )
  560.                                     {
  561.                                       CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  562. #ifdef DELTAWPA8
  563.                                       CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  564.                                       deltamap = prevnode -> fn_ChunkyMap;
  565. #endif /* DELTAWPA8 */
  566.                                     }
  567.                                     else
  568.                                     {
  569. #ifdef DELTAWPA8
  570.                                       deltamap = NULL;
  571. #endif /* DELTAWPA8 */
  572.                                     }
  573.                                 }
  574.                                     break;
  575.  
  576.                                 default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
  577.                                 {
  578.                                     error_printf( cb, gaid, "unsupported disposal method %lu\n", (ULONG)(gaid -> gaid_GIFDec . Gif89 . disposal) );
  579.                                 }
  580.                                     break;
  581.                               }
  582.  
  583.                               if( !useGlobalColormap )
  584.                               {
  585.                                 /* Skip colormap (in buffer) */
  586.                                 gifdec -> buffer += (sizeof( struct ColorRegister ) * bitPixel);
  587.                               }
  588.  
  589.                               ReadImage( cb, gaid,
  590.                                          (fn -> fn_ChunkyMap),
  591.                                          (UWORD)animwidth,
  592.                                          LOHI2UINT16( buf[ 0 ], buf[ 1 ] ),
  593.                                          LOHI2UINT16( buf[ 2 ], buf[ 3 ] ),
  594.                                          LOHI2UINT16( buf[ 4 ], buf[ 5 ] ),
  595.                                          LOHI2UINT16( buf[ 6 ], buf[ 7 ] ),
  596.                                          BitSet( buf[ 8 ], INTERLACE ),
  597.                                          FALSE,
  598.                                          (worknode -> fn_GIF89aTransparent) );
  599.                             }
  600.  
  601.                             FreeVec( (gifdec -> file_buffer) );
  602.                             gifdec -> file_buffer = gifdec -> buffer = NULL;
  603.                           }
  604.  
  605.                           /* Bump file pos */
  606.                           gaid -> gaid_CurrFilePos = Seek( (gaid -> gaid_FH), 0L, OFFSET_CURRENT ); /* BUG: does not check for failure */
  607.                         }
  608.                         else
  609.                         {
  610.                           /* seek failed */
  611.                           error = IoErr();
  612.                           break;
  613.                         }
  614.  
  615.                         prevnode = NULL; /* a previous image is now in our chunkymap,
  616.                                           * we don't need the link anymore
  617.                                           */
  618.                       }
  619.                     } while( rollback-- );
  620.  
  621.                     if( error == 0L )
  622.                     {
  623.                       if( fn -> fn_ChunkyMap )
  624.                       {
  625.                         if( gaid -> gaid_UseChunkyMap )
  626.                         {
  627.                           WriteRGBPixelArray8( cb, (fn -> fn_BitMap), animwidth, animheight, (fn -> fn_ColorMap), (fn -> fn_ChunkyMap) );
  628.                         }
  629.                         else
  630.                         {
  631.                           WriteDeltaPixelArray8Fast( (fn -> fn_BitMap), (fn -> fn_ChunkyMap), deltamap );
  632.                         }
  633.                       }
  634.                     }
  635.                   }
  636.                   else
  637.                   {
  638.                     /* can't alloc bitmap */
  639.                     error = ERROR_NO_FREE_STORE;
  640.                   }
  641.                 }
  642.                 else
  643.                 {
  644.                   /* can't alloc chunkymap */
  645.                   error = ERROR_NO_FREE_STORE;
  646.                 }
  647.               }
  648.             }
  649.  
  650.             /* Store timing/context information */
  651.             alf -> alf_Duration = fn -> fn_Duration;
  652.             alf -> alf_Frame    = fn -> fn_Frame;
  653.             alf -> alf_UserData = (APTR)fn;        /* Links back to this FrameNode (used by ADTM_UNLOADFRAME) */
  654.  
  655.             /* Store bitmap information */
  656.             alf -> alf_BitMap = fn -> fn_BitMap;
  657.             alf -> alf_CMap   = ((gaid -> gaid_UseChunkyMap)?(NULL):(fn -> fn_CMap)); /* we does not use a colormap with a direct RGB-coded bitmap */
  658.  
  659.             /* Is there a sample to play ? */
  660.             if( fn -> fn_Sample )
  661.             {
  662.               /* Store sound information */
  663.               alf -> alf_Sample       = fn -> fn_Sample;
  664.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  665.               alf -> alf_Period       = fn -> fn_Period;
  666.             }
  667.             else
  668.             {
  669.               /* No sound */
  670.               alf -> alf_Sample       = NULL;
  671.               alf -> alf_SampleLength = 0UL;
  672.               alf -> alf_Period       = 0UL;
  673.             }
  674.  
  675.             /* Frame "in use", even for a unsuccessful result; on error
  676.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  677.              * allocated resources and decreases the "UseCount"...
  678.              */
  679.             fn -> fn_UseCount++;
  680.  
  681.             /* Return bitmap ptr of possible, 0UL and error cause otherwise */
  682.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  683.           }
  684.           else
  685.           {
  686.             /* no matching frame found */
  687.             error = ERROR_OBJECT_NOT_FOUND;
  688.           }
  689.  
  690.           /* Like "realloc": Free any given frame here */
  691.           if( freeframe . alf_UserData )
  692.           {
  693.             freeframe . MethodID = ADTM_UNLOADFRAME;
  694.             DoMethodA( o, (Msg)(&freeframe) );
  695.           }
  696.  
  697.           SetIoErr( error ); /* Result2 */
  698.  
  699.           ReleaseSemaphore( (&(gaid -> gaid_SigSem)) );
  700.       }
  701.           break;
  702.  
  703. /****** gifanim.datatype/ADTM_UNLOADFRAME ************************************
  704. *
  705. *    NAME
  706. *        ADTM_UNLOADFRAME -- Unload frame contents
  707. *
  708. *    FUNCTION
  709. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  710. *        animation frame.
  711. *
  712. *        This method frees the bitmap data found in adtFrame.
  713. *
  714. *    RESULT
  715. *        Returns always 0UL.
  716. *
  717. ******************************************************************************
  718. *
  719. */
  720.       case ADTM_UNLOADFRAME:
  721.       {
  722.           struct FrameNode *fn;
  723.           struct adtFrame  *alf;
  724.  
  725.           gaid = (struct GIFAnimInstData *)INST_DATA( cl, o );
  726.           alf = (struct adtFrame *)msg;
  727.  
  728.           /* Free bitmaps only if we don't cache the whole anim */
  729.           if( (gaid -> gaid_LoadAll) == FALSE )
  730.           {
  731.             ObtainSemaphore( (&(gaid -> gaid_SigSem)) );
  732.  
  733.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  734.             {
  735.               if( (fn -> fn_UseCount) > 0 )
  736.               {
  737.                 fn -> fn_UseCount--;
  738.  
  739.                 /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  740.                 if( ((fn -> fn_UseCount) == 0) && (fn -> fn_BitMap) && (fn != (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head)) )
  741.                 {
  742.                   FreeFrameBitMap( cb, gaid, (fn -> fn_BitMap) );
  743.                   FreeVecPooled( cb, (gaid -> gaid_Pool), (fn -> fn_ChunkyMap) );
  744.                   fn -> fn_BitMap    = NULL;
  745.                   fn -> fn_ChunkyMap = NULL;
  746.                 }
  747.               }
  748.             }
  749.  
  750.             ReleaseSemaphore( (&(gaid -> gaid_SigSem)) );
  751.           }
  752.  
  753.           /* The frame has been freed ! */
  754.           alf -> alf_UserData = NULL;
  755.       }
  756.           break;
  757.  
  758.       /* Let the superclass handle everything else */
  759.       default:
  760.       {
  761.           retval = DoSuperMethodA( cl, o, msg );
  762.       }
  763.           break;
  764.     }
  765.  
  766.     return( retval );
  767. }
  768.  
  769.  
  770. static
  771. BOOL ScanFrames( struct ClassBase *cb, Object *o )
  772. {
  773.     struct GIFAnimInstData *gaid    = (struct GIFAnimInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  774.     LONG                    error   = 0L;
  775.     BOOL                    success = FALSE;
  776.  
  777.     InitSemaphore( (&(gaid -> gaid_SigSem)) );
  778.     NewList( (struct List *)(&(gaid -> gaid_FrameList)) );
  779.  
  780.     /* Create a memory pool for frame nodes */
  781.     if( gaid -> gaid_Pool = CreatePool( MEMF_PUBLIC, 8192UL, 8192UL ) )
  782.     {
  783.       BPTR                 fh;                             /* handle (file handle)      */
  784.       ULONG                sourcetype;                     /* type of stream (either DTST_FILE or DTST_RAM) */
  785.       ULONG                modeid /*= (ULONG)INVALID_ID*/; /* anim view mode                  */
  786.       ULONG                animwidth,                      /* anim width                      */
  787.                            animheight,                     /* anim height                     */
  788.                            animdepth;                      /* anim depth                      */
  789.       ULONG                timestamp  = 0UL;               /* timestamp                       */
  790.  
  791.       /* Prefs defaults */
  792.       gaid -> gaid_LoadAll = TRUE;              /* The decoder is too slow to allow realtime decoding of a
  793.                                                  * 576 * 124 * 8 GIF Image, even on a mc68040 :-((
  794.                                                  */
  795.       gaid -> gaid_ModeID  = (ULONG)INVALID_ID; /* no screen mode selected yet */
  796.       gaid -> gaid_Volume  = 64UL;
  797.  
  798.       /* Read prefs */
  799.       ReadENVPrefs( cb, gaid, NULL );
  800.  
  801.       /* Get file handle, handle type and BitMapHeader */
  802.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  803.                          DTA_Handle,        (&fh),
  804.                          DTA_Name,          (&(gaid -> gaid_ProjectName)),
  805.                          TAG_DONE ) == 3UL )
  806.       {
  807.         switch( sourcetype )
  808.         {
  809.           case DTST_FILE:
  810.           {
  811.               if( fh )
  812.               {
  813.                 BPTR lock;
  814.  
  815.                 if( lock = DupLockFromFH( fh ) )
  816.                 {
  817.                   /* Set up a filehandle for disk-based loading (random loading) */
  818.                   if( gaid -> gaid_FH = (LONG)OpenFromLock( lock ) )
  819.                   {
  820.                     success = TRUE;
  821.                   }
  822.                   else
  823.                   {
  824.                     /* failure */
  825.                     UnLock( lock );
  826.                   }
  827.                 }
  828.               }
  829.  
  830.               /* OpenFromLock failed ? - Then open by name :-( */
  831.               if( (gaid -> gaid_FH) == NULL )
  832.               {
  833.                 /* Set up a filehandle for disk-based loading (random loading) */
  834.                 if( gaid -> gaid_FH = (LONG)Open( (gaid -> gaid_ProjectName), MODE_OLDFILE ) )
  835.                 {
  836.                   success = TRUE;
  837.                 }
  838.                 else
  839.                 {
  840.                   /* Can't open file */
  841.                   error = IoErr();
  842.                 }
  843.               }
  844.           }
  845.               break;
  846.  
  847.           case DTST_RAM: /* empty object */
  848.           {
  849.               success = TRUE;
  850.           }
  851.               break;
  852.  
  853.           default:
  854.           {
  855.               /* unsupported source type */
  856.               error = ERROR_NOT_IMPLEMENTED;
  857.           }
  858.               break;
  859.         }
  860.  
  861.         /* Any error ? */
  862.         if( success )
  863.         {
  864.           /* Now we enter the next stage of testing... */
  865.           success = FALSE;
  866.  
  867.           if( fh )
  868.           {
  869.             struct GIFDecoder    *gifdec                           = (&(gaid -> gaid_GIFDec));
  870.             struct FrameNode     *fn;
  871.             ULONG                 numcmaps                         = 0UL; /* number of created cmaps */
  872.             UBYTE                 buf[ 16 ];
  873.             struct ColorRegister  localColorMap[ MAXCOLORMAPSIZE ] = { 0 };
  874.             struct ColorRegister  savedTransparentColor            = { 0 };
  875.             UBYTE                 c;
  876.             BOOL                  useGlobalColormap;
  877.             UWORD                 bitPixel;
  878.             UBYTE                 version[ 4 ];
  879.  
  880.             gifdec -> file                = fh;
  881.             gifdec -> Gif89 . transparent = (UWORD)~0U; /* means: no transparent color */
  882.  
  883.             /* Read "GIF" indentifer and version */
  884.             if( ReadOK( cb, gifdec, buf, 6 ) )
  885.             {
  886.               /* Is there the GIF signature ? */
  887.               if( !strncmp( (char *)buf, "GIF", 3 ) )
  888.               {
  889.                 strncpy( version, (char *)(buf + 3), 3 );
  890.                 version[ 3 ] = '\0';
  891.  
  892.                 /* Check if we support this GIF version */
  893.                 if( (!strcmp( version, "87a" )) ||
  894.                     (!strcmp( version, "89a" )) )
  895.                 {
  896.                   /* Read GIF Screen */
  897.                   if( ReadOK( cb, gifdec, buf, 7 ) )
  898.                   {
  899.                     struct FrameNode *prevnode = NULL;
  900.                     UBYTE            *deltamap = NULL;
  901.  
  902.                     gifdec -> GifScreen . Width           = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
  903.                     gifdec -> GifScreen . Height          = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
  904.                     gifdec -> GifScreen . BitPixel        = 2 << (buf[ 4 ] & 0x07);
  905.                     gifdec -> GifScreen . ColorResolution = (((buf[ 4 ] & 0x70) >> 3) + 1);
  906.                     gifdec -> GifScreen . Background      = buf[ 5 ];
  907.                     gifdec -> GifScreen . AspectRatio     = buf[ 6 ];
  908.  
  909.                                  gaid -> gaid_Width        = gifdec -> GifScreen . Width;
  910.                     animwidth  = gaid -> gaid_PaddedWidth  = (gaid -> gaid_UseChunkyMap)?(gaid -> gaid_Width):(((gaid -> gaid_Width) + 15UL) & ~15UL); /* align for c2p-wpa (c2c does not need padding) */
  911.                     animheight = gaid -> gaid_Height       = gifdec -> GifScreen . Height;
  912.                     animdepth  = gaid -> gaid_Depth        = (gaid -> gaid_UseChunkyMap)?(DIRECTRGB_DEPTH):((ULONG)getbase2( (gifdec -> GifScreen . BitPixel) ));
  913.  
  914.                     /* Global Colormap ? */
  915.                     if( BitSet( buf[ 4 ], LOCALCOLORMAP ) )
  916.                     {
  917.                       numcmaps++;
  918.  
  919.                       if( ReadColorMap( cb, gaid, (gifdec -> GifScreen . BitPixel), (gifdec -> GifScreen . ColorMap) ) )
  920.                       {
  921.                         error = IoErr();
  922.                         D( kprintf( "error reading global colormap\n" ) );
  923.                       }
  924.                     }
  925.                     else
  926.                     {
  927.                       /* No global colormap ? - Then the background color in the GifScreen is a NOP */
  928.                       gifdec -> GifScreen . Background = 0U;
  929.                     }
  930.  
  931.                     for( ;; )
  932.                     {
  933.                       /* Read chunk ID char */
  934.                       if( !ReadOK( cb, gifdec, (&c), 1 ) )
  935.                       {
  936.                         error = IoErr();
  937.                         D( kprintf( "EOF / read error on image data\n" ) );
  938.                       }
  939.  
  940.                       switch( c )
  941.                       {
  942.                         case ';': /* GIF terminator ? */
  943.                         {
  944.                             goto scandone;
  945.                         }
  946.  
  947.                         case '!': /* Extension ? */
  948.                         {
  949.                             if( !ReadOK( cb, gifdec, (&c), 1 ) )
  950.                             {
  951.                               error = IoErr();
  952.                               D( kprintf( "OF / read error on extension function code\n" ) );
  953.                             }
  954.  
  955.                             DoExtension( cb, o, gaid, c );
  956.                         }
  957.                             break;
  958.  
  959.                         case ',': /* Raster data start ? */
  960.                         {
  961.                             /* Create an prepare a new frame node */
  962.                             if( fn = AllocFrameNode( cb, (gaid -> gaid_Pool) ) )
  963.                             {
  964.                               if( (gaid -> gaid_LoadAll) || (timestamp == 0UL) )
  965.                               {
  966.                                 if( !(fn -> fn_BitMap = AllocFrameBitMap( cb, gaid ) ) )
  967.                                 {
  968.                                   error = ERROR_NO_FREE_STORE;
  969.                                 }
  970.  
  971.                                 /* Allocate array for chunkypixel data */
  972.                                 if( fn -> fn_ChunkyMap = (UBYTE *)AllocVecPooled( cb, (gaid -> gaid_Pool), ((animwidth * animheight) + 256) ) )
  973.                                 {
  974.                                   /* Get a clean background to avoid that rubbish shows througth transparent parts */
  975.                                   memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  976.                                 }
  977.                                 else
  978.                                 {
  979.                                   error = ERROR_NO_FREE_STORE;
  980.                                 }
  981.                               }
  982.  
  983.                               if( error == 0L )
  984.                               {
  985.                                 ULONG duration;
  986.  
  987.                                 /* Get position of bitmap */
  988.                                 fn -> fn_BMOffset = Seek( fh, 0L, OFFSET_CURRENT ); /* BUG: does not check for failure */
  989.  
  990.                                 D( kprintf( "pos %lu\n", (fn -> fn_BMOffset) ) );
  991.  
  992.                                 if( !ReadOK( cb, gifdec, buf, 9 ) )
  993.                                 {
  994.                                   error = IoErr();
  995.                                   D( kprintf( "couldn't read left/top/width/height\n" ) );
  996.                                 }
  997.  
  998.                                 /* Local color map ? */
  999.                                 useGlobalColormap = !BitSet( buf[ 8 ], LOCALCOLORMAP );
  1000.  
  1001.                                 /* Size of local color map */
  1002.                                 bitPixel = 1 << ((buf[ 8 ] & 0x07) + 1);
  1003.  
  1004.                                 /* Store GIF89a related attributes */
  1005.                                 fn -> fn_GIF89aDisposal    = gifdec -> Gif89 . disposal;    /* Store disposal mode for current frame  */
  1006.                                 fn -> fn_GIF89aTransparent = gifdec -> Gif89 . transparent; /* Store currents frame transparent color */
  1007.  
  1008.                                 if( fn -> fn_ChunkyMap )
  1009.                                 {
  1010.                                   /* disposal method */
  1011.                                   switch( fn -> fn_GIF89aDisposal )
  1012.                                   {
  1013.                                     case GIF89A_DISPOSE_NOP:
  1014.                                     {
  1015.                                         /* Background not transparent ? */
  1016.                                         if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1017.                                             ((fn -> fn_GIF89aTransparent) != 0U) )
  1018.                                         {
  1019.                                           /* restore to color 0 */
  1020.                                           memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1021.                                         }
  1022.                                     }
  1023.                                         break;
  1024.  
  1025.                                     case GIF89A_DISPOSE_NODISPOSE:
  1026.                                     {
  1027.                                         /* do not dispose prev image */
  1028.  
  1029.                                         /* If we have a previous frame, copy it  */
  1030.                                         if( prevnode )
  1031.                                         {
  1032.                                           CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  1033. #ifdef DELTAWPA8
  1034.                                           CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  1035.                                           deltamap = prevnode -> fn_ChunkyMap;
  1036. #endif /* DELTAWPA8 */
  1037.                                         }
  1038.                                         else
  1039.                                         {
  1040.                                           /* Background not transparent ? */
  1041.                                           if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1042.                                               ((fn -> fn_GIF89aTransparent) != 0U) )
  1043.                                           {
  1044.                                             /* restore to color 0 */
  1045.                                             memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1046.                                           }
  1047. #ifdef DELTAWPA8
  1048.                                           deltamap = NULL;
  1049. #endif /* DELTAWPA8 */
  1050.                                         }
  1051.                                     }
  1052.                                         break;
  1053.  
  1054.                                     case GIF89A_DISPOSE_RESTOREBACKGROUND:
  1055.                                     {
  1056.                                         /* Background not transparent ? */
  1057.                                         if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
  1058.                                             ((fn -> fn_GIF89aTransparent) != (gaid -> gaid_GIFDec . GifScreen . Background)) )
  1059.                                         {
  1060.                                           /* Restore to background color */
  1061.                                           memset( (fn -> fn_ChunkyMap), (gifdec -> GifScreen . Background), (size_t)(animwidth * animheight) );
  1062.                                         }
  1063.                                     }
  1064.                                         break;
  1065.  
  1066.                                     case GIF89A_DISPOSE_RESTOREPREVIOUS:
  1067.                                     {
  1068.                                         /* restore previous image  */
  1069.  
  1070.                                         /* If we have a previous frame, copy it  */
  1071.                                         if( prevnode )
  1072.                                         {
  1073.                                           CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
  1074. #ifdef DELTAWPA8
  1075.                                           CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
  1076.                                           deltamap = prevnode -> fn_ChunkyMap;
  1077. #endif /* DELTAWPA8 */
  1078.                                         }
  1079.                                         else
  1080.                                         {
  1081.                                           /* restore to color 0 */
  1082.                                           memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
  1083. #ifdef DELTAWPA8
  1084.                                           deltamap = NULL;
  1085. #endif /* DELTAWPA8 */
  1086.                                         }
  1087.                                     }
  1088.                                         break;
  1089.  
  1090.                                     default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
  1091.                                     {
  1092.                                         error_printf( cb, gaid, "unsupported disposal method %lu\n", (ULONG)(gifdec -> Gif89 . disposal) );
  1093.                                     }
  1094.                                         break;
  1095.                                   }
  1096.                                 }
  1097.  
  1098.                                 /* Save transparent color (if we have one) */
  1099.                                 if( ((fn -> fn_GIF89aTransparent) != ~0U) && (timestamp != 0UL) )
  1100.                                 {
  1101.                                   savedTransparentColor = localColorMap[ (fn -> fn_GIF89aTransparent) ];
  1102.                                 }
  1103.  
  1104.                                 /* Get colormap */
  1105.                                 if( useGlobalColormap )
  1106.                                 {
  1107.                                   /* use global colormap and depth */
  1108.                                   bitPixel = gifdec -> GifScreen . BitPixel;
  1109.                                   memcpy( localColorMap, (gifdec -> GifScreen . ColorMap), (sizeof( struct ColorRegister ) * bitPixel) );
  1110.                                 }
  1111.                                 else
  1112.                                 {
  1113.                                   numcmaps++;
  1114.  
  1115.                                   if( ReadColorMap( cb, gaid, bitPixel, localColorMap ) )
  1116.                                   {
  1117.                                     error_printf( cb, gaid, "error reading local colormap\n" );
  1118.                                     error = IoErr();
  1119.                                   }
  1120.                                 }
  1121.  
  1122.                                 /* Restore transparent color (if we have one) */
  1123.                                 if( (fn -> fn_GIF89aTransparent) != ~0U )
  1124.                                 {
  1125.                                   localColorMap[ (fn -> fn_GIF89aTransparent) ] = savedTransparentColor;
  1126.                                 }
  1127.  
  1128.                                 if( !(gaid -> gaid_UseChunkyMap) )
  1129.                                 {
  1130.                                   /* The first palette must be moved to the object's palette */
  1131.                                   if( timestamp == 0UL )
  1132.                                   {
  1133.                                     if( !CMAP2Object( cb, o, (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) ) )
  1134.                                     {
  1135.                                       /* can't alloc object's color table */
  1136.                                       error = ERROR_NO_FREE_STORE;
  1137.                                     }
  1138.                                   }
  1139.  
  1140.                                   /* Create a palette-per-frame colormap here */
  1141.                                   if( !(fn -> fn_CMap = CMAP2ColorMap( cb, (1UL << (ULONG)(gaid -> gaid_Depth)), (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) )) )
  1142.                                   {
  1143.                                     /* can't alloc colormap */
  1144.                                     error = ERROR_NO_FREE_STORE;
  1145.                                   }
  1146.                                 }
  1147.  
  1148.                                 /* Copy colormap for 24 bit output */
  1149.                                 memcpy( (void *)(fn -> fn_ColorMap), (void *)localColorMap, (size_t)(sizeof( struct ColorRegister ) * bitPixel) );
  1150.  
  1151.                                 ReadImage( cb, gaid,
  1152.                                            (fn -> fn_ChunkyMap),
  1153.                                            (UWORD)animwidth,
  1154.                                            LOHI2UINT16( buf[ 0 ], buf[ 1 ] ),
  1155.                                            LOHI2UINT16( buf[ 2 ], buf[ 3 ] ),
  1156.                                            LOHI2UINT16( buf[ 4 ], buf[ 5 ] ),
  1157.                                            LOHI2UINT16( buf[ 6 ], buf[ 7 ] ),
  1158.                                            BitSet( buf[ 8 ], INTERLACE ),
  1159.                                            ((fn -> fn_BitMap) == NULL),
  1160.                                            (fn -> fn_GIF89aTransparent) );
  1161.  
  1162.                                 /* Get size of bitmap (curr_pos - start_of_bm) */
  1163.                                 fn -> fn_BMSize = Seek( fh, 0L, OFFSET_CURRENT ) - (fn -> fn_BMOffset); /* BUG: does not check for failure */
  1164.  
  1165.                                 if( fn -> fn_BitMap )
  1166.                                 {
  1167.                                   if( gaid -> gaid_UseChunkyMap )
  1168.                                   {
  1169.                                     WriteRGBPixelArray8( cb, (fn -> fn_BitMap), animwidth, animheight, (fn -> fn_ColorMap), (fn -> fn_ChunkyMap) );
  1170.                                   }
  1171.                                   else
  1172.                                   {
  1173.                                     WriteDeltaPixelArray8Fast( (fn -> fn_BitMap), (fn -> fn_ChunkyMap), deltamap );
  1174.                                   }
  1175.                                 }
  1176.  
  1177.                                 /* Bump timestamp... */
  1178.                                 if( ((gifdec -> Gif89 . delayTime) != ~0U) &&
  1179.                                     ((gifdec -> Gif89 . delayTime) > 1U)   &&
  1180.                                     ((gifdec -> Gif89 . delayTime) < 2000U) )
  1181.                                 {
  1182.                                   duration = (gifdec -> Gif89 . delayTime);
  1183.                                 }
  1184.                                 else
  1185.                                 {
  1186.                                   duration = 0UL;
  1187.                                 }
  1188.  
  1189.                                 fn -> fn_TimeStamp = timestamp;
  1190.                                 fn -> fn_Frame     = timestamp;
  1191.                                 fn -> fn_Duration  = duration;
  1192.  
  1193.                                 AddTail( (struct List *)(&(gaid -> gaid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  1194.  
  1195.                                 prevnode = fn;
  1196.  
  1197.                                 /* Next frame starts at timestamp... */
  1198.                                 timestamp += (fn -> fn_Duration) + 1UL;
  1199.                               }
  1200.                             }
  1201.                         }
  1202.                             break;
  1203.                             
  1204.                         case 0x00: /* padding byte ? */
  1205.                         {
  1206.                             /* Padding bytes are not part of the Compuserve documents, but... */
  1207.                             if( !(gaid -> gaid_StrictSyntax) )
  1208.                             {
  1209.                               break;
  1210.                             }
  1211.                         }
  1212.  
  1213.                         default: /* Not a valid raster data start character ? */
  1214.                         {
  1215.                             error_printf( cb, gaid, "invalid character 0x%02x, ignoring\n", (int)c );
  1216.                         }
  1217.                             break;
  1218.                       }
  1219.  
  1220.                       /* on error break */
  1221.                       if( error )
  1222.                       {
  1223.                         break;
  1224.                       }
  1225.                     }
  1226.  
  1227. scandone:
  1228.                     /* Any frames ? */
  1229.                     if( timestamp && (error == 0L) && numcmaps )
  1230.                     {
  1231.                       if( numcmaps == 1UL )
  1232.                       {
  1233.                         /* We only have a global colormap and no colormap changes (or a direct RGB bitmap),
  1234.                          * delete first colormap (a colormap in the first frames indicates following colormap
  1235.                          * changes)
  1236.                          */
  1237.                         struct FrameNode *firstnode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1238.  
  1239.                         if( firstnode -> fn_CMap )
  1240.                         {
  1241.                           FreeColorMap( (firstnode -> fn_CMap) );
  1242.                           firstnode -> fn_CMap = NULL;
  1243.                         }
  1244.                       }
  1245.                       else
  1246.                       {
  1247.                         /* All frames must have a colormap, therefore we replicate the colormap
  1248.                          * from the previous colormap if one is missing
  1249.                          */
  1250.                         struct FrameNode *worknode,
  1251.                                          *nextnode;
  1252.                         struct ColorMap  *currcm = NULL;
  1253.  
  1254.                         verbose_printf( cb, gaid, "Animation has palette changes per frame\n" );
  1255.  
  1256.                         worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1257.  
  1258.                         while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1259.                         {
  1260.                           if( worknode -> fn_CMap )
  1261.                           {
  1262.                             /* Current node contains colormap, this are the colors for the following frames... */
  1263.                             currcm = worknode -> fn_CMap;
  1264.                           }
  1265.                           else
  1266.                           {
  1267.                             if( currcm )
  1268.                             {
  1269.                               /* Copy colormap from previous one... */
  1270.                               if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
  1271.                               {
  1272.                                 /* Can't copy/alloc colormap */
  1273.                                 error = ERROR_NO_FREE_STORE;
  1274.                               }
  1275.                             }
  1276.                             else
  1277.                             {
  1278.                               verbose_printf( cb, gaid, "scan/load: no colormap, can't copy it\n" );
  1279.                             }
  1280.                           }
  1281.  
  1282.                           worknode = nextnode;
  1283.                         }
  1284.                       }
  1285.                     }
  1286.  
  1287.                     /* Check for required information */
  1288.                     if( error == 0L )
  1289.                     {
  1290.                       /* Any frames loaded ? */
  1291.                       if( timestamp == 0UL )
  1292.                       {
  1293.                         /* not enougth frames (at least one required) */
  1294.                         error = DTERROR_NOT_ENOUGH_DATA;
  1295.                       }
  1296.                     }
  1297.  
  1298.                     /* Any error ? */
  1299.                     if( error == 0L )
  1300.                     {
  1301.                       struct FrameNode *firstfn = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head); /* short cut to the first FrameNode */
  1302.  
  1303.                       /* Alloc bitmap as key bitmap */
  1304.                       if( gaid -> gaid_UseChunkyMap )
  1305.                       {
  1306.                         gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL );
  1307.                       }
  1308.                       else
  1309.                       {
  1310.                         gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, BMF_CLEAR, NULL );
  1311.                       }
  1312.  
  1313.                       if( gaid -> gaid_KeyBitMap )
  1314.                       {
  1315.                         if( (firstfn -> fn_BitMap) == NULL )
  1316.                         {
  1317.                           /* can't alloc first bitmap */
  1318.                           error = ERROR_NO_FREE_STORE;
  1319.                         }
  1320.  
  1321.                         if( error == 0L )
  1322.                         {
  1323.                           /* Copy first frame into key bitmap */
  1324.                           CopyBitMap( cb, (gaid -> gaid_KeyBitMap), (firstfn -> fn_BitMap), animwidth, animheight );
  1325.  
  1326.                           /* No screen mode id set by prefs ? */
  1327.                           if( (gaid -> gaid_ModeID) != (ULONG)INVALID_ID )
  1328.                           {
  1329.                             modeid = gaid -> gaid_ModeID;
  1330.                           }
  1331.                           else
  1332.                           {
  1333.                             if( gaid -> gaid_UseChunkyMap )
  1334.                             {
  1335.                               /* We don't have fixed values for cybergfx mode id's, therefore we have to ask for them */
  1336.                               if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth,  animwidth,
  1337.                                                              CYBRBIDTG_NominalHeight, animheight,
  1338.                                                              CYBRBIDTG_Depth,         animdepth,
  1339.                                                              TAG_DONE )) == INVALID_ID )
  1340.                               {
  1341. #if 0
  1342.                                 error = 1L; /* inducate an error here :-( */
  1343. #else
  1344.                                 /* Workaround for CyberGFX bug :-( */
  1345.                                 if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth,  640UL,
  1346.                                                                CYBRBIDTG_NominalHeight, 480UL,
  1347.                                                                CYBRBIDTG_Depth,         animdepth,
  1348.                                                                TAG_DONE )) == INVALID_ID )
  1349.                                 {
  1350.                                   modeid = 0UL;
  1351.  
  1352.                                   error_printf( cb, gaid, "'CyberGFX bug' workaround failed, too\n" );
  1353.                                 }
  1354. #endif
  1355.  
  1356.                                 error_printf( cb, gaid, "No screenmode available for %lu/%lu/%lu\n", animwidth, animheight, animdepth );
  1357.                               }
  1358.                             }
  1359.                             else
  1360.                             {
  1361.                               /* BUG: Does currently not support SUPERHIRES modes */
  1362.                               if( animwidth >= 640UL )
  1363.                               {
  1364.                                 if( animheight >= 400 )
  1365.                                 {
  1366.                                   modeid = HIRESLACE_KEY;
  1367.                                 }
  1368.                                 else
  1369.                                 {
  1370.                                   modeid = HIRES_KEY;
  1371.                                 }
  1372.                               }
  1373.                               else
  1374.                               {
  1375.                                 if( animheight >= 400 )
  1376.                                 {
  1377.                                   modeid = LORESLACE_KEY;
  1378.                                 }
  1379.                                 else
  1380.                                 {
  1381.                                   modeid = LORES_KEY;
  1382.                                 }
  1383.                               }
  1384.                             }
  1385.                           }
  1386.  
  1387.                           /* No fps set by prefs ? */
  1388.                           if( (gaid -> gaid_FPS) == 0UL )
  1389.                           {
  1390.                             gaid -> gaid_FPS = 100; /* defaults to 100 fps. GIF 89a delay values counts in
  1391.                                                      * 1/100 sec steps. We set the alf_Duration field
  1392.                                                      * to this value (got from the GIF 89a extension).
  1393.                                                      */
  1394.                           }
  1395.  
  1396.                           AttachSample( cb, gaid );
  1397.  
  1398.                           verbose_printf( cb, gaid, "width %lu height %lu depth %lu frames %lu fps %lu\n",
  1399.                                           animwidth,
  1400.                                           animheight,
  1401.                                           animdepth,
  1402.                                           timestamp,
  1403.                                           (gaid -> gaid_FPS) );
  1404.  
  1405.                           /* Set misc attributes */
  1406.                           SetDTAttrs( o, NULL, NULL,
  1407.                                       DTA_ObjName,                                       (gaid -> gaid_ProjectName),
  1408.                                       DTA_TotalHoriz,                                    animwidth,
  1409.                                       DTA_TotalVert,                                     animheight,
  1410.                                       ADTA_Width,                                        (gaid -> gaid_Width),
  1411.                                       ADTA_Height,                                       animheight,
  1412.                                       ADTA_Depth,                                        animdepth,
  1413.                                       ADTA_Frames,                                       timestamp,
  1414.                                       ADTA_FramesPerSecond,                              (gaid -> gaid_FPS),
  1415.                                       ADTA_ModeID,                                       modeid,
  1416.                                       ADTA_KeyFrame,                                     (gaid -> gaid_KeyBitMap),
  1417.                                       XTAG( (firstfn -> fn_Sample), ADTA_Sample       ), (firstfn -> fn_Sample),
  1418.                                       XTAG( (firstfn -> fn_Sample), ADTA_SampleLength ), ((firstfn -> fn_SampleLength) / ((firstfn -> fn_Duration) + 1UL)),
  1419.                                       XTAG( (firstfn -> fn_Sample), ADTA_Period       ), (firstfn -> fn_Period),
  1420.                                       XTAG( (firstfn -> fn_Sample), ADTA_Volume       ), (gaid -> gaid_Volume),
  1421.                                       TAG_DONE );
  1422.  
  1423.                           /* All done for now... */
  1424.                           success = TRUE;
  1425.                         }
  1426.                       }
  1427.                       else
  1428.                       {
  1429.                         /* can't alloc key bitmap */
  1430.                         error = ERROR_NO_FREE_STORE;
  1431.                       }
  1432.                     }
  1433.                   }
  1434.                   else
  1435.                   {
  1436.                     error = IoErr();
  1437.                     D( kprintf( "failed to read screen descriptor\n" ) );
  1438.                   }
  1439.                 }
  1440.                 else
  1441.                 {
  1442.                   error = DTERROR_UNKNOWN_COMPRESSION;
  1443.                   D( kprintf( "bad version number, not '87a' or '89a'\n" ) );
  1444.                 }
  1445.               }
  1446.               else
  1447.               {
  1448.                 error = ERROR_OBJECT_WRONG_TYPE;
  1449.                 D( kprintf( "not a GIF file\n" ) );
  1450.               }
  1451.             }
  1452.             else
  1453.             {
  1454.               error = IoErr();
  1455.               D( kprintf( "error reading magic number\n" ) );
  1456.             }
  1457.  
  1458.             /* Prepare decoder for dynamic frame access */
  1459.             gifdec -> file = gaid -> gaid_FH;
  1460.           }
  1461.           else
  1462.           {
  1463.             /* No file handle ? - Be sure we got a DTST_RAM sourcetype */
  1464.             if( sourcetype == DTST_RAM )
  1465.             {
  1466.               /* The object is used without any input file.
  1467.                * This "empty" object is used to run the encoder only...
  1468.                */
  1469.               success = TRUE;
  1470.             }
  1471.             else
  1472.             {
  1473.               /* No handle ! */
  1474.               error = ERROR_REQUIRED_ARG_MISSING;
  1475.             }
  1476.           }
  1477.         }
  1478.       }
  1479.       else
  1480.       {
  1481.         /* can't get required attributes from superclass */
  1482.         error = ERROR_OBJECT_WRONG_TYPE;
  1483.       }
  1484.     }
  1485.     else
  1486.     {
  1487.       /* no memory pool */
  1488.       error = ERROR_NO_FREE_STORE;
  1489.     }
  1490.  
  1491.     SetIoErr( error );
  1492.  
  1493.     return( success );
  1494. }
  1495.  
  1496.  
  1497. static
  1498. struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
  1499. {
  1500.     struct FrameNode *fn;
  1501.  
  1502.     if( fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) )
  1503.     {
  1504.       memset( fn, 0, sizeof( struct FrameNode ) );
  1505.     }
  1506.  
  1507.     return( fn );
  1508. }
  1509.  
  1510.  
  1511. static
  1512. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  1513. {
  1514.     if( fnl )
  1515.     {
  1516.       struct FrameNode *worknode,
  1517.                        *nextnode,
  1518.                        *prevnode;
  1519.  
  1520.       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1521.  
  1522.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1523.       {
  1524.         if( (worknode -> fn_TimeStamp) > timestamp )
  1525.         {
  1526.           return( prevnode );
  1527.         }
  1528.  
  1529.         prevnode = worknode;
  1530.         worknode = nextnode;
  1531.       }
  1532.  
  1533.       if( !IsListEmpty( ((struct List *)fnl) ) )
  1534.       {
  1535.         return( prevnode );
  1536.       }
  1537.     }
  1538.  
  1539.     return( NULL );
  1540. }
  1541.  
  1542.  
  1543. static
  1544. void FreeFrameNodeResources( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1545. {
  1546.     struct FrameNode *worknode;
  1547.  
  1548. /* The follwoing was used for debugging */
  1549. /* #define FREE_LIST_IN_REVERSE_ORDER 1 */
  1550.  
  1551. #ifdef FREE_LIST_IN_REVERSE_ORDER
  1552.     struct FrameNode *nextnode;
  1553.  
  1554.     worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1555.  
  1556.     while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1557. #else
  1558.     while( worknode = (struct FrameNode *)RemTail( (struct List *)(&(gaid -> gaid_FrameList)) ) )
  1559. #endif /* FREE_LIST_IN_REVERSE_ORDER */
  1560.     {
  1561.       if( worknode -> fn_CMap )
  1562.       {
  1563.         FreeColorMap( (worknode -> fn_CMap) );
  1564.         worknode -> fn_CMap = NULL;
  1565.       }
  1566.  
  1567.       if( worknode -> fn_BitMap )
  1568.       {
  1569.         FreeFrameBitMap( cb, gaid, (worknode -> fn_BitMap) );
  1570.         worknode -> fn_BitMap = NULL;
  1571.       }
  1572.  
  1573. #ifdef FREE_LIST_IN_REVERSE_ORDER
  1574.       worknode = nextnode;
  1575. #endif /* FREE_LIST_IN_REVERSE_ORDER */
  1576.     }
  1577. }
  1578.  
  1579.  
  1580. static
  1581. struct BitMap *AllocFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1582. {
  1583.     if( gaid -> gaid_UseChunkyMap )
  1584.     {
  1585.       return( AllocBitMap( (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth),
  1586.                            (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL ) );
  1587.     }
  1588.     else
  1589.     {
  1590.       return( AllocBitMapPooled( cb, (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth), (gaid -> gaid_Pool) ) );
  1591.     }
  1592. }
  1593.  
  1594.  
  1595. static
  1596. void FreeFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, struct BitMap *bm )
  1597. {
  1598.     if( bm )
  1599.     {
  1600.       if( gaid -> gaid_UseChunkyMap )
  1601.       {
  1602.         FreeBitMap( bm );
  1603.       }
  1604.       else
  1605.       {
  1606.         FreeVecPooled( cb, (gaid -> gaid_Pool), bm );
  1607.       }
  1608.     }
  1609. }
  1610.  
  1611.  
  1612. /* This function assumes (0UL < depth) && (depth <= 8UL) */
  1613. static
  1614. struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
  1615. {
  1616.     struct BitMap *bm;
  1617.  
  1618.     ULONG          planesize,
  1619.                    size;
  1620.  
  1621.     planesize = (ULONG)RASSIZE( width, height ) + 16UL;
  1622.     size      = ((ULONG)sizeof( struct BitMap )) + (planesize * depth) + width;
  1623.  
  1624.     if( bm = (struct BitMap *)AllocVecPooled( cb, pool, size ) )
  1625.     {
  1626.       UWORD    pl;
  1627.       PLANEPTR plane;
  1628.  
  1629.       InitBitMap( bm, depth, width, height );
  1630.  
  1631.       plane = (PLANEPTR)(bm + 1); /* First plane follows struct BitMap */
  1632.  
  1633.       /* Set up plane data */
  1634.       pl = 0U;
  1635.  
  1636.       /* Set up plane ptrs */
  1637.       while( pl < depth )
  1638.       {
  1639.         bm -> Planes[ pl ] = plane;
  1640.  
  1641.         plane = (PLANEPTR)(((UBYTE *)plane) + planesize + 8);
  1642.         pl++;
  1643.       }
  1644.  
  1645.       /* Clear the remaining plane ptrs */
  1646.       while( pl < 8U )
  1647.       {
  1648.         bm -> Planes[ pl ] = NULL;
  1649.  
  1650.         pl++;
  1651.       }
  1652.     }
  1653.  
  1654.     return( bm );
  1655. }
  1656.  
  1657.  
  1658. void OpenLogfile( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1659. {
  1660.     if( (gaid -> gaid_VerboseOutput) == NULL )
  1661.     {
  1662.       STRPTR confile;
  1663.  
  1664.       if( confile = (STRPTR)AllocVec( (((gaid -> gaid_ProjectName)?(strlen( (gaid -> gaid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  1665.       {
  1666.         mysprintf( cb, confile, "CON:////GIF Anim DataType %s/auto/wait/close/inactive",
  1667.                    ((gaid -> gaid_ProjectName)?(FilePart( (gaid -> gaid_ProjectName) )):(NULL)) );
  1668.  
  1669.         gaid -> gaid_VerboseOutput = Open( confile, MODE_READWRITE );
  1670.  
  1671.         FreeVec( confile );
  1672.       }
  1673.     }
  1674. }
  1675.  
  1676.  
  1677. void error_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
  1678. {
  1679.     OpenLogfile( cb, gaid );
  1680.  
  1681.     if( gaid -> gaid_VerboseOutput )
  1682.     {
  1683.       VFPrintf( (gaid -> gaid_VerboseOutput), format, (APTR)((&format) + 1) );
  1684.     }
  1685. }
  1686.  
  1687.  
  1688. void verbose_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
  1689. {
  1690.     if( gaid -> gaid_VerboseOutput )
  1691.     {
  1692.       VFPrintf( (gaid -> gaid_VerboseOutput), format, (APTR)((&format) + 1) );
  1693.     }
  1694. }
  1695.  
  1696.  
  1697. static
  1698. void AttachSample( struct ClassBase *cb, struct GIFAnimInstData *gaid )
  1699. {
  1700.     if( gaid -> gaid_Sample )
  1701.     {
  1702.       struct FrameNode *worknode,
  1703.                        *nextnode;
  1704.  
  1705.       ULONG             period          = gaid -> gaid_Period;
  1706.       ULONG             samplesperframe;
  1707.       BYTE             *sample          = gaid -> gaid_Sample;
  1708.  
  1709.       samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (gaid -> gaid_FPS) * 2UL));
  1710.  
  1711.       if( gaid -> gaid_SamplesPerFrame )
  1712.       {
  1713.         period = (period * samplesperframe) / (gaid -> gaid_SamplesPerFrame);
  1714.  
  1715.         samplesperframe = gaid -> gaid_SamplesPerFrame;
  1716.  
  1717.         verbose_printf( cb, gaid, "period corrected from %lu to %lu to match spf=%lu with fps=%lu\n",
  1718.                         (gaid -> gaid_Period), period, samplesperframe, (gaid -> gaid_FPS) );
  1719.       }
  1720.  
  1721.       verbose_printf( cb, gaid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
  1722.                       (SysBase -> ex_EClockFrequency), period, (gaid -> gaid_FPS), (gaid -> gaid_SampleLength), samplesperframe );
  1723.  
  1724.       worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
  1725.  
  1726.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1727.       {
  1728.         worknode -> fn_Sample       = sample;
  1729.         worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
  1730.         worknode -> fn_Period       = period;
  1731.  
  1732.         sample += worknode -> fn_SampleLength;
  1733.  
  1734.         /* End of sample reached ? */
  1735.         if( (ULONG)(sample - (gaid -> gaid_Sample)) > (gaid -> gaid_SampleLength) )
  1736.         {
  1737.           /* Cut last size of sample to fit */
  1738.           worknode -> fn_SampleLength -= (ULONG)(sample - (gaid -> gaid_Sample));
  1739.  
  1740.           break;
  1741.         }
  1742.  
  1743.         worknode = nextnode;
  1744.       }
  1745.     }
  1746. }
  1747.  
  1748.  
  1749. static
  1750. BOOL ReadColorMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, UWORD numcolors, struct ColorRegister *color )
  1751. {
  1752.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1753.  
  1754.     return( (BOOL)(!ReadOK( cb, gifdec, color, (ULONG)(sizeof( struct ColorRegister ) * numcolors) )) );
  1755. }
  1756.  
  1757.  
  1758. static
  1759. void DoExtension( struct ClassBase *cb, Object *o, struct GIFAnimInstData *gaid, TEXT label )
  1760. {
  1761.     struct GIFDecoder *gifdec     = (&(gaid -> gaid_GIFDec));
  1762.     UBYTE              buf[ 256 ] = { 0 };
  1763.     STRPTR             str;
  1764.  
  1765.     switch( label )
  1766.     {
  1767.       case 0x01:              /* Plain Text Extension */
  1768.       {
  1769.           UWORD lpos,
  1770.                 tpos,
  1771.                 width,
  1772.                 height,
  1773.                 cellw,
  1774.                 cellh,
  1775.                 foreground,
  1776.                 background;
  1777.  
  1778.           error_printf( cb, gaid, "'Plain text extension' not supported yet. Please send this animation to the author that"
  1779.                                   "this can be implemented\n" );
  1780.  
  1781.           (void)GetDataBlock( cb, gaid, buf );
  1782.  
  1783.           lpos       = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
  1784.           tpos       = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
  1785.           width      = LOHI2UINT16( buf[ 4 ], buf[ 5 ] );
  1786.           height     = LOHI2UINT16( buf[ 6 ], buf[ 7 ] );
  1787.           cellw      = buf[ 8 ];
  1788.           cellh      = buf[ 9 ];
  1789.           foreground = buf[ 10 ];
  1790.           background = buf[ 11 ];
  1791.  
  1792.           verbose_printf( cb, gaid, "Plain text: "
  1793.                                     "left %lu top %lu width %lu height %lu "
  1794.                                     "cell width %lu cell height %lu"
  1795.                                     "foreground %lu background %lu", lpos, tpos, width, height, cellw, cellh, foreground, background );
  1796.  
  1797.           while( GetDataBlock( cb, gaid, buf ) != 0 )
  1798.           {
  1799. #if 0
  1800.             PPM_ASSIGN( image[ ypos ][ xpos ], cmap[ CM_RED ][ v ], cmap[ CM_GREEN ][ v ], cmap[ CM_BLUE ][ v ] );
  1801.  
  1802.             index++;
  1803. #endif
  1804.  
  1805.             /* Clear buffer for next cycle */
  1806.             memset( (void *)buf, 0, sizeof( buf ) );
  1807.           }
  1808.  
  1809.           return;
  1810.       }
  1811.  
  1812.       case 0xf9:              /* Graphic Control Extension */
  1813.       {
  1814.           STRPTR fmt; /* Format string for verbose output (fmt changes if transparent color is set) */
  1815.  
  1816.           (void)GetDataBlock( cb, gaid, buf );
  1817.  
  1818.           /* Get "delta" mode (disposal of previous frame), input flag and the delay time in 1/100 sec) */
  1819.           gifdec -> Gif89 . disposal    = (buf[ 0 ] >> 2) & 0x7;
  1820.           gifdec -> Gif89 . inputFlag   = (buf[ 0 ] >> 1) & 0x1;
  1821.           gifdec -> Gif89 . delayTime   = LOHI2UINT16( buf[ 1 ], buf[ 2 ] );
  1822.  
  1823.           /* Any transparent color ? */
  1824.           if( buf[ 0 ] & 0x01 )
  1825.           {
  1826.             gifdec -> Gif89 . transparent = buf[ 3 ];
  1827.  
  1828.             fmt = "Graphic Control Extension: disposal %s (%lu)%s transparent %lu\n";
  1829.           }
  1830.           else
  1831.           {
  1832.             fmt = "Graphic Control Extension: disposal %s (%lu)%s\n";
  1833.           }
  1834.  
  1835.           /* Verbose output ? */
  1836.           if( gaid -> gaid_VerboseOutput )
  1837.           {
  1838.             STRPTR user_input = ((gifdec -> Gif89 . inputFlag)?(" user input requested"):(""));
  1839.             STRPTR disposal;
  1840.  
  1841.             switch( gifdec -> Gif89 . disposal )
  1842.             {
  1843.               case GIF89A_DISPOSE_NOP:                  disposal = "nop";                break;
  1844.               case GIF89A_DISPOSE_NODISPOSE:            disposal = "no dispose";         break;
  1845.               case GIF89A_DISPOSE_RESTOREBACKGROUND:    disposal = "restore background"; break;
  1846.               case GIF89A_DISPOSE_RESTOREPREVIOUS:      disposal = "restore previous";   break;
  1847.               default:                                  disposal = "reserved";           break;
  1848.             }
  1849.  
  1850.             verbose_printf( cb, gaid, fmt,
  1851.                                       disposal,
  1852.                                       (ULONG)(gifdec -> Gif89 . disposal),
  1853.                                       user_input,
  1854.                                       (gifdec -> Gif89 . transparent) );
  1855.           }
  1856.  
  1857.           /* Ignore remaining data... */
  1858.           while( GetDataBlock( cb, gaid, (UBYTE *)buf ) != 0 )
  1859.                   ;
  1860.  
  1861.           return;
  1862.       }
  1863.  
  1864.       case 0xfe:              /* Comment Extension */
  1865.       {
  1866.           STRPTR annotation;
  1867.  
  1868.           /* Get all comment extension chunks, and append them on the DTA_ObjAnnotation string we've created before */
  1869.           while( GetDataBlock( cb, gaid, buf ) != 0 )
  1870.           {
  1871.             ULONG  size;
  1872.             STRPTR oldannotation;
  1873.  
  1874.             buf[ 255 ] = '\0'; /* terminate explicitly */
  1875.  
  1876.             size = (ULONG)strlen( buf ) + 2UL;
  1877.  
  1878.             (void)GetDTAttrs( o, DTA_ObjAnnotation, (&oldannotation), TAG_DONE );
  1879.  
  1880.             if( oldannotation )
  1881.             {
  1882.               size += (ULONG)strlen( oldannotation ) + 2UL;
  1883.             }
  1884.  
  1885.             /* Allocate a temp buffer */
  1886.             if( annotation = (STRPTR)AllocMem( size, MEMF_ANY ) )
  1887.             {
  1888.               if( oldannotation )
  1889.               {
  1890.                 strcpy( annotation, oldannotation );
  1891.               }
  1892.               else
  1893.               {
  1894.                 annotation[ 0 ] = '\0'; /* terminate */
  1895.               }
  1896.  
  1897.               /* Append the new buffer */
  1898.               IBMPC2ISOLatin1( buf, (annotation + strlen( annotation )) );
  1899.  
  1900.               /* Store the comment */
  1901.               SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, annotation, TAG_DONE );
  1902.  
  1903.               /* Free temp string */
  1904.               FreeMem( annotation, size );
  1905.             }
  1906.  
  1907.             /* Clear buffer for next cycle */
  1908.             memset( (void *)buf, 0, sizeof( buf ) );
  1909.           }
  1910.  
  1911.           /* After all, prompt the annotation to the user */
  1912.           (void)GetDTAttrs( o, DTA_ObjAnnotation, (&annotation), TAG_DONE );
  1913.  
  1914.           verbose_printf( cb, gaid, "Comment Extension: '%s'\n", annotation );
  1915.  
  1916.           return;
  1917.       }
  1918.  
  1919.       case 0xff:              /* Application Extension */
  1920.       {
  1921.           str = "Application Extension";
  1922.       }
  1923.           break;
  1924.  
  1925.       default:
  1926.       {
  1927.           mysprintf( cb, buf, "UNKNOWN (0x%02lx)", (long)label );
  1928.           str = buf;
  1929.       }
  1930.           break;
  1931.     }
  1932.  
  1933.     verbose_printf( cb, gaid, "got a '%s' extension\n", ((str)?(str):"") );
  1934.  
  1935.     /* skip extension data */
  1936.     while( GetDataBlock( cb, gaid, buf ) != 0 )
  1937.       ;
  1938.  
  1939.     return;
  1940. }
  1941.  
  1942.  
  1943. static
  1944. int GetDataBlock( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *buf )
  1945. {
  1946.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1947.     UBYTE              count;
  1948.  
  1949.     if( !ReadOK( cb, gifdec, &count, 1 ) )
  1950.     {
  1951.       error_printf( cb, gaid, "error in getting DataBlock size\n" );
  1952.  
  1953.       return( -1 );
  1954.     }
  1955.  
  1956.     gifdec -> ZeroDataBlock = (count == 0);
  1957.  
  1958.     if( (count != 0) && (!ReadOK( cb, gifdec, buf, (ULONG)count ) ) )
  1959.     {
  1960.       error_printf( cb, gaid, "error in reading DataBlock\n" );
  1961.  
  1962.       return( -1 );
  1963.     }
  1964.  
  1965.     return( count );
  1966. }
  1967.  
  1968.  
  1969. static
  1970. int GetCode( struct ClassBase *cb, struct GIFAnimInstData *gaid, int code_size, BOOL flag )
  1971. {
  1972.     int                i,
  1973.                        j,
  1974.                        ret;
  1975.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  1976.     UBYTE              count;
  1977.  
  1978.     if( flag )
  1979.     {
  1980.       gifdec -> GetCode . curbit  = 0;
  1981.       gifdec -> GetCode . lastbit = 0;
  1982.       gifdec -> GetCode . done    = FALSE;
  1983.  
  1984.       return( 0 );
  1985.     }
  1986.  
  1987.     if( (gifdec -> GetCode . curbit + code_size) >= gifdec -> GetCode . lastbit )
  1988.     {
  1989.       if( gifdec -> GetCode . done )
  1990.       {
  1991.         if( gifdec -> GetCode . curbit >= gifdec -> GetCode . lastbit )
  1992.           D( kprintf( "ran off the end of my bits\n" ) );
  1993.  
  1994.         return( -1 );
  1995.       }
  1996.  
  1997.       gifdec -> GetCode . buf[ 0 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 2 ];
  1998.       gifdec -> GetCode . buf[ 1 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 1 ];
  1999.  
  2000.       if( (count = GetDataBlock( cb, gaid, &gifdec -> GetCode . buf[ 2 ] ) ) == 0 )
  2001.         gifdec -> GetCode . done = TRUE;
  2002.  
  2003.       gifdec -> GetCode . last_byte = 2 + count;
  2004.       gifdec -> GetCode . curbit    = (gifdec -> GetCode . curbit - gifdec -> GetCode . lastbit) + 16;
  2005.       gifdec -> GetCode . lastbit   = (2 + count) * 8 ;
  2006.     }
  2007.  
  2008.     ret = 0;
  2009.  
  2010.     for( i = gifdec -> GetCode . curbit, j = 0; j < code_size ; i++, j++ )
  2011.       ret |= ((gifdec -> GetCode . buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  2012.  
  2013.     gifdec -> GetCode . curbit += code_size;
  2014.  
  2015.     return( ret );
  2016. }
  2017.  
  2018.  
  2019. static
  2020. int LWZReadByte( struct ClassBase *cb, struct GIFAnimInstData *gaid, BOOL flag, int input_code_size )
  2021. {
  2022.              int                code,
  2023.                                 incode;
  2024.     register int                i;
  2025.              struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  2026.  
  2027.     if( flag )
  2028.     {
  2029.       gifdec -> LWZReadByte . set_code_size = input_code_size;
  2030.       gifdec -> LWZReadByte . code_size     = gifdec -> LWZReadByte . set_code_size + 1;
  2031.       gifdec -> LWZReadByte . clear_code    = 1 << gifdec -> LWZReadByte . set_code_size ;
  2032.       gifdec -> LWZReadByte . end_code      = gifdec -> LWZReadByte . clear_code + 1;
  2033.       gifdec -> LWZReadByte . max_code_size = 2 * gifdec -> LWZReadByte . clear_code;
  2034.       gifdec -> LWZReadByte . max_code      = gifdec -> LWZReadByte . clear_code + 2;
  2035.  
  2036.       GetCode( cb, gaid, 0, TRUE );
  2037.  
  2038.       gifdec -> LWZReadByte . fresh = TRUE;
  2039.  
  2040.       /* Fill table with the codes... */
  2041.       for( i = 0 ; i < (gifdec -> LWZReadByte . clear_code) ; i++ )
  2042.       {
  2043.         gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
  2044.         gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
  2045.       }
  2046.  
  2047.       /* ... and clear the remaining part  */
  2048.       for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
  2049.       {
  2050.         gifdec -> LWZReadByte . table[ 0 ][ i ] =
  2051.           gifdec -> LWZReadByte . table[ 1 ][ 0 ] = 0;
  2052.       }
  2053.  
  2054.       /* Reset stack ptr */
  2055.       gifdec -> LWZReadByte . sp = gifdec -> LWZReadByte . stack;
  2056.  
  2057.       return( 0 );
  2058.     }
  2059.     else
  2060.     {
  2061.       if( gifdec -> LWZReadByte . fresh )
  2062.       {
  2063.         gifdec -> LWZReadByte . fresh = FALSE;
  2064.  
  2065.         do
  2066.         {
  2067.           gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . oldcode = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
  2068.         } while( gifdec -> LWZReadByte . firstcode == gifdec -> LWZReadByte . clear_code );
  2069.  
  2070.         return( gifdec -> LWZReadByte . firstcode );
  2071.       }
  2072.     }
  2073.  
  2074.     if( gifdec -> LWZReadByte . sp > gifdec -> LWZReadByte . stack )
  2075.     {
  2076.       return( *--gifdec -> LWZReadByte . sp );
  2077.     }
  2078.  
  2079.     while( (code = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE )) >= 0 )
  2080.     {
  2081.       if( code == gifdec -> LWZReadByte . clear_code )
  2082.       {
  2083.         for( i = 0 ; i < gifdec -> LWZReadByte . clear_code ; i++ )
  2084.         {
  2085.           gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
  2086.           gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
  2087.         }
  2088.  
  2089.         for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
  2090.         {
  2091.           gifdec -> LWZReadByte . table[ 0 ][ i ] =
  2092.             gifdec -> LWZReadByte . table[ 1 ][ i ] = 0;
  2093.         }
  2094.  
  2095.         gifdec -> LWZReadByte . code_size       = gifdec -> LWZReadByte . set_code_size + 1;
  2096.         gifdec -> LWZReadByte . max_code_size   = 2 * gifdec -> LWZReadByte . clear_code;
  2097.         gifdec -> LWZReadByte . max_code        = gifdec -> LWZReadByte . clear_code + 2;
  2098.         gifdec -> LWZReadByte . sp              = gifdec -> LWZReadByte . stack;
  2099.         gifdec -> LWZReadByte . firstcode       =
  2100.           gifdec -> LWZReadByte . oldcode       = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
  2101.  
  2102.         return( gifdec -> LWZReadByte . firstcode );
  2103.       }
  2104.       else
  2105.       {
  2106.         if( code == gifdec -> LWZReadByte . end_code )
  2107.         {
  2108.           int   count;
  2109.           UBYTE buf[ 260 ];
  2110.  
  2111.           if( gifdec -> ZeroDataBlock )
  2112.             return( -2 );
  2113.  
  2114.           while( (count = GetDataBlock( cb, gaid, buf )) > 0 )
  2115.             ;
  2116.  
  2117.           if( count != 0 )
  2118.             error_printf( cb, gaid, "missing EOD in data stream (common occurence)\n" );
  2119.  
  2120.           return( -2 );
  2121.         }
  2122.       }
  2123.  
  2124.       incode = code;
  2125.  
  2126.       if( code >= gifdec -> LWZReadByte . max_code )
  2127.       {
  2128.         *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode;
  2129.         code = gifdec -> LWZReadByte . oldcode;
  2130.       }
  2131.  
  2132.       while( code >= gifdec -> LWZReadByte . clear_code )
  2133.       {
  2134.         *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . table[ 1 ][ code ];
  2135.  
  2136.         if( code == gifdec -> LWZReadByte . table[ 0 ][ code ] )
  2137.           D( kprintf( "circular table entry BIG ERROR\n" ) );
  2138.  
  2139.         code = gifdec -> LWZReadByte . table[ 0 ][ code ];
  2140.       }
  2141.  
  2142.       *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . table[ 1 ][ code ];
  2143.  
  2144.       if( (code = gifdec -> LWZReadByte . max_code) < (1 << MAX_LWZ_BITS ) )
  2145.       {
  2146.         gifdec -> LWZReadByte . table[ 0 ][ code ] = gifdec -> LWZReadByte . oldcode;
  2147.         gifdec -> LWZReadByte . table[ 1 ][ code ] = gifdec -> LWZReadByte . firstcode;
  2148.         gifdec -> LWZReadByte . max_code++;
  2149.  
  2150.         if( (gifdec -> LWZReadByte . max_code >= gifdec -> LWZReadByte . max_code_size) && (gifdec -> LWZReadByte . max_code_size < (1 << MAX_LWZ_BITS)) )
  2151.         {
  2152.           gifdec -> LWZReadByte . max_code_size *= 2;
  2153.           gifdec -> LWZReadByte . code_size++;
  2154.         }
  2155.       }
  2156.  
  2157.       gifdec -> LWZReadByte . oldcode = incode;
  2158.  
  2159.       if( gifdec -> LWZReadByte . sp > gifdec -> LWZReadByte . stack )
  2160.       {
  2161.         return( *--gifdec -> LWZReadByte . sp );
  2162.       }
  2163.     }
  2164.  
  2165.     return( code );
  2166. }
  2167.  
  2168.  
  2169. static
  2170. void ReadImage( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *image,
  2171.                 UWORD imagewidth, UWORD left, UWORD top, UWORD len, UWORD height,
  2172.                 BOOL interlace, BOOL ignore, UWORD transparent )
  2173. {
  2174.     struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
  2175.     UBYTE              c;
  2176.  
  2177.     /* Initialize the Compression routines */
  2178.     (void)ReadOK( cb, gifdec, &c, 1 );
  2179.  
  2180.     /* If this is an "uninteresting picture" ignore it. */
  2181.     if( ignore )
  2182.     {
  2183.       D( kprintf( cb, gaid, "skipping gif image...\n" ) );
  2184.  
  2185.       /* Loop until end of raster data */
  2186.       for( ;; )
  2187.       {
  2188.         if( !ReadOK( cb, gifdec, &c, 1 ) )
  2189.           D( kprintf( "EOF / reading block byte count\n" ) );
  2190.  
  2191.         if( c == 0 )
  2192.         {
  2193.           D( kprintf( cb, gaid, "gif image done\n" ) );
  2194.           break;
  2195.         }
  2196.  
  2197.         /* Skip... */
  2198.         (void)Seek( (gifdec -> file), (long)c, OFFSET_CURRENT );
  2199.       }
  2200.     }
  2201.     else
  2202.     {
  2203.        WORD v;
  2204.       ULONG xpos    = 0UL,
  2205.             ypos    = 0UL,
  2206.             offset  = (top * imagewidth) + left,
  2207.             pass    = 0UL;
  2208.  
  2209.       if( LWZReadByte( cb, gaid, TRUE, c ) < 0 )
  2210.         D( kprintf( "error reading image\n" ) );
  2211.  
  2212.       D( kprintf( cb, gaid, "reading %lx %ld.%ld / %ld by %ld%s GIF image\n", image, left, top, len, height, interlace ? " interlaced" : "" ) );
  2213.  
  2214.       while( (v = LWZReadByte( cb, gaid, FALSE, c )) >= 0 )
  2215.       {
  2216.         /* Pixel transparent ? */
  2217.         if( (transparent == ~0U) ||
  2218.             (transparent != v) )
  2219.         {
  2220.           /* Store pixel */
  2221.           image[ offset + xpos ] = v;
  2222.         }
  2223.  
  2224.         xpos++;
  2225.  
  2226.         if( xpos == len )
  2227.         {
  2228.           xpos = 0UL;
  2229.  
  2230.           if( interlace )
  2231.           {
  2232.             switch( pass )
  2233.             {
  2234.               case 0UL:
  2235.               case 1UL: ypos += 8UL; break;
  2236.               case 2UL: ypos += 4UL; break;
  2237.               case 3UL: ypos += 2UL; break;
  2238.             }
  2239.  
  2240.             if( ypos >= height )
  2241.             {
  2242.               pass++;
  2243.  
  2244.               switch( pass )
  2245.               {
  2246.                 case 1UL: ypos = 4UL;  break;
  2247.                 case 2UL: ypos = 2UL;  break;
  2248.                 case 3UL: ypos = 1UL;  break;
  2249.                 default: goto fini;
  2250.               }
  2251.             }
  2252.           }
  2253.           else
  2254.           {
  2255.             ypos++;
  2256.           }
  2257.  
  2258.           offset = ((ypos + top) * imagewidth) + left;
  2259.         }
  2260.  
  2261.         if( ypos >= height )
  2262.           break;
  2263.       }
  2264.  
  2265. fini:
  2266.       if( (v = LWZReadByte( cb, gaid, FALSE, c )) >= 0 )
  2267.       {
  2268.         /* 0x00-bytes are treated here as padding bytes unless the STRICTSYNTAX option is set... */
  2269.         if( (v != 0) || (gaid -> gaid_StrictSyntax) )
  2270.         {
  2271.           verbose_printf( cb, gaid, "too much input data %ld, ignoring extra...\n", (long)v );
  2272.         }
  2273.       }
  2274.     }
  2275. }
  2276.  
  2277.  
  2278. /* got from my anim.datatype */
  2279. static
  2280. struct FrameNode *GetPrevFrameNode( struct FrameNode *currfn, ULONG interleave )
  2281. {
  2282.     struct FrameNode *worknode,
  2283.                      *prevnode;
  2284.  
  2285.     /* Get previous frame */
  2286.     worknode = currfn;
  2287.  
  2288.     while( prevnode = (struct FrameNode *)(worknode -> fn_Node . mln_Pred) )
  2289.     {
  2290.       if( (interleave-- == 0U) || ((prevnode -> fn_Node . mln_Pred) == NULL) )
  2291.       {
  2292.         break;
  2293.       }
  2294.  
  2295.       worknode = prevnode;
  2296.     }
  2297.  
  2298.     return( worknode );
  2299. }
  2300.  
  2301.  
  2302. /* WritePixelArray8 replacement by Peter McGavin (p.mcgavin@irl.cri.nz),
  2303.  * slightly adapted to fit here...
  2304.  */
  2305.  
  2306. static
  2307. void WriteDeltaPixelArray8Fast( struct BitMap *dest, UBYTE *source, UBYTE *prev )
  2308. {
  2309.              ULONG *plane[ 8 ] = { 0 };
  2310.     register ULONG *chunky     = (ULONG *)source, /* fetch 32 bits per cycle */
  2311.                    *prevchunky = (ULONG *)prev;
  2312.              ULONG  numcycles  = ((dest -> Rows) * (dest -> BytesPerRow)) / sizeof( ULONG ),
  2313.                     i;
  2314.  
  2315.     /* Copy plane ptrs */
  2316.     for( i = 0UL ; i < (dest -> Depth) ; i++ )
  2317.     {
  2318.       plane[ i ] = (ULONG *)(dest -> Planes[ i ]);
  2319.     }
  2320.  
  2321.     /* Fill unused planes with plane 0, which will be written last, all previous accesses
  2322.      * will be droped (assumes that a cache hides this "dummy" writes)
  2323.      */
  2324.     for( i ; i < 8UL ; i++ )
  2325.     {
  2326.       plane[ i ] = (ULONG *)(dest -> Planes[ 0 ]);
  2327.     }
  2328.  
  2329. #define merge( a, b, mask, shift ) \
  2330.       tmp = mask & (a ^ (b >> shift));   \
  2331.       a ^= tmp;                          \
  2332.       b ^= (tmp << shift)
  2333.  
  2334.     /* Check if we have to do the "delta" test */
  2335.     if( prevchunky )
  2336.     {
  2337.       /* Process bitmaps */
  2338.       for( i = 0UL ; i < numcycles ; i++ )
  2339.       {
  2340.         register ULONG b0, b1, b2, b3, b4, b5, b6, b7,
  2341.                        tmp;
  2342.  
  2343.         /* process 32 pixels */
  2344.         b0 = *chunky++;  b4 = *chunky++;
  2345.         b1 = *chunky++;  b5 = *chunky++;
  2346.         b2 = *chunky++;  b6 = *chunky++;
  2347.         b3 = *chunky++;  b7 = *chunky++;
  2348.  
  2349.         /* I use the '+' here to avoid that the compiler skips an expression.
  2350.          * WARNING: The code assumes that the code is executed in the sequence as it occurs here
  2351.          */
  2352.         if( (b0 != *prevchunky++) + (b4 != *prevchunky++) +
  2353.             (b1 != *prevchunky++) + (b5 != *prevchunky++) +
  2354.             (b2 != *prevchunky++) + (b6 != *prevchunky++) +
  2355.             (b3 != *prevchunky++) + (b7 != *prevchunky++) )
  2356.         {
  2357.           merge( b0, b2, 0x0000ffff, 16 );
  2358.           merge( b1, b3, 0x0000ffff, 16 );
  2359.           merge( b4, b6, 0x0000ffff, 16 );
  2360.           merge( b5, b7, 0x0000ffff, 16 );
  2361.  
  2362.           merge( b0, b1, 0x00ff00ff,  8 );
  2363.           merge( b2, b3, 0x00ff00ff,  8 );
  2364.           merge( b4, b5, 0x00ff00ff,  8 );
  2365.           merge( b6, b7, 0x00ff00ff,  8 );
  2366.  
  2367.           merge( b0, b4, 0x0f0f0f0f,  4 );
  2368.           merge( b1, b5, 0x0f0f0f0f,  4 );
  2369.           merge( b2, b6, 0x0f0f0f0f,  4 );
  2370.           merge( b3, b7, 0x0f0f0f0f,  4 );
  2371.  
  2372.           merge( b0, b2, 0x33333333,  2 );
  2373.           merge( b1, b3, 0x33333333,  2 );
  2374.           merge( b4, b6, 0x33333333,  2 );
  2375.           merge( b5, b7, 0x33333333,  2 );
  2376.  
  2377.           merge( b0, b1, 0x55555555,  1 );
  2378.           merge( b2, b3, 0x55555555,  1 );
  2379.           merge( b4, b5, 0x55555555,  1 );
  2380.           merge( b6, b7, 0x55555555,  1 );
  2381.  
  2382.           *plane[ 7 ]++ = b0;
  2383.           *plane[ 6 ]++ = b1;
  2384.           *plane[ 5 ]++ = b2;
  2385.           *plane[ 4 ]++ = b3;
  2386.           *plane[ 3 ]++ = b4;
  2387.           *plane[ 2 ]++ = b5;
  2388.           *plane[ 1 ]++ = b6;
  2389.           *plane[ 0 ]++ = b7;
  2390.         }
  2391.         else
  2392.         {
  2393.           plane[ 7 ]++;
  2394.           plane[ 6 ]++;
  2395.           plane[ 5 ]++;
  2396.           plane[ 4 ]++;
  2397.           plane[ 3 ]++;
  2398.           plane[ 2 ]++;
  2399.           plane[ 1 ]++;
  2400.           plane[ 0 ]++;
  2401.         }
  2402.       }
  2403.     }
  2404.     else
  2405.     {
  2406.       /* Process bitmaps */
  2407.       for( i = 0UL ; i < numcycles ; i++ )
  2408.       {
  2409.         register ULONG b0, b1, b2, b3, b4, b5, b6, b7,
  2410.                        tmp;
  2411.  
  2412.         /* process 32 pixels */
  2413.         b0 = *chunky++;  b4 = *chunky++;
  2414.         b1 = *chunky++;  b5 = *chunky++;
  2415.         b2 = *chunky++;  b6 = *chunky++;
  2416.         b3 = *chunky++;  b7 = *chunky++;
  2417.  
  2418.         merge( b0, b2, 0x0000ffff, 16 );
  2419.         merge( b1, b3, 0x0000ffff, 16 );
  2420.         merge( b4, b6, 0x0000ffff, 16 );
  2421.         merge( b5, b7, 0x0000ffff, 16 );
  2422.  
  2423.         merge( b0, b1, 0x00ff00ff,  8 );
  2424.         merge( b2, b3, 0x00ff00ff,  8 );
  2425.         merge( b4, b5, 0x00ff00ff,  8 );
  2426.         merge( b6, b7, 0x00ff00ff,  8 );
  2427.  
  2428.         merge( b0, b4, 0x0f0f0f0f,  4 );
  2429.         merge( b1, b5, 0x0f0f0f0f,  4 );
  2430.         merge( b2, b6, 0x0f0f0f0f,  4 );
  2431.         merge( b3, b7, 0x0f0f0f0f,  4 );
  2432.  
  2433.         merge( b0, b2, 0x33333333,  2 );
  2434.         merge( b1, b3, 0x33333333,  2 );
  2435.         merge( b4, b6, 0x33333333,  2 );
  2436.         merge( b5, b7, 0x33333333,  2 );
  2437.  
  2438.         merge( b0, b1, 0x55555555,  1 );
  2439.         merge( b2, b3, 0x55555555,  1 );
  2440.         merge( b4, b5, 0x55555555,  1 );
  2441.         merge( b6, b7, 0x55555555,  1 );
  2442.  
  2443.         *plane[ 7 ]++ = b0;
  2444.         *plane[ 6 ]++ = b1;
  2445.         *plane[ 5 ]++ = b2;
  2446.         *plane[ 4 ]++ = b3;
  2447.         *plane[ 3 ]++ = b4;
  2448.         *plane[ 2 ]++ = b5;
  2449.         *plane[ 1 ]++ = b6;
  2450.         *plane[ 0 ]++ = b7;
  2451.       }
  2452.     }
  2453. }
  2454.  
  2455.  
  2456. static
  2457. int getbase2( int x )
  2458. {
  2459.     int i = 0,
  2460.         j = 1;
  2461.  
  2462.     while( x > j )
  2463.     {
  2464.       j *= 2;
  2465.       i++;
  2466.     }
  2467.  
  2468.     return( i );
  2469. }
  2470.  
  2471.  
  2472.  
  2473.  
  2474. /* Read and test */
  2475. static
  2476. BOOL ReadOK( struct ClassBase *cb, struct GIFDecoder *gifdec, void *buffer, ULONG len )
  2477. {
  2478.     if( (gifdec -> which_fh) == WHICHFH_FILE )
  2479.     {
  2480.       return( (BOOL)(Read( (gifdec -> file), buffer, len ) == len) );
  2481.     }
  2482.     else
  2483.     {
  2484.       /* Check if the request fit in out buffer... */
  2485.       if( (((gifdec -> buffer) - (gifdec -> file_buffer)) + len) <= (gifdec -> buffersize) )
  2486.       {
  2487.         CopyMem( (gifdec -> buffer), buffer, len );
  2488.         gifdec -> buffer += len;
  2489.  
  2490.         return( TRUE );
  2491.       }
  2492.     }
  2493.  
  2494.     return( FALSE );
  2495. }
  2496.  
  2497.  
  2498.  
  2499.  
  2500.  
  2501.  
  2502.